原始笔记

Deep Learning on Cloud Nine

Deep Learning on Cloud Nine(整理版)

原始资料: CS197 Harvard Lectures 14 & 15 - Deep Learning on Cloud Nine created: 2026-07-10 11:01 整理说明: 本版本结合原始笔记和可读取的原始教程重排、补全和翻译。原教程包含 AWS EC2 教程,但本笔记按当前实践选择暂时跳过 AWS 创建流程,重点整理组内 GPU 使用、GPU 监控、数据下载和 CheXzero 训练准备。

内容简要概括

这节课讨论如何从本地开发转向云端或远程 GPU 环境进行 deep learning 实验,核心是让代码、数据加载和训练流程真正使用 GPU。原教程以 AWS EC2 为主要平台,但当前笔记将实践重点切换到组内 GPU:需要先确认 GPU 状态,再配置 conda 环境、监控训练资源、下载大规模数据,并为 CheXzero / MIMIC-CXR 这类医学影像训练任务准备数据。最值得记住的是:有 GPU 不等于代码会自动使用 GPU,模型、输入张量、DataLoader 参数和依赖版本都需要一起检查。

GPUnvidia-smiCUDAcondaW&BDataLoadernum_workersbatch sizewgettmuxPhysioNetMIMIC-CXRCheXzeroHDF5

目录


1. 学习目标与实践取舍

原始教程的主题是 “Deep Learning on Cloud Nine”,主要通过 AWS EC2 演示如何创建 GPU instance、连接远程机器、修改训练代码并运行 CheXzero。当前笔记的实际取舍是:

  • 暂时跳过 AWS 服务器创建和连接教程。
  • 改为使用组内已有 GPU 服务器。
  • 保留原教程中与 GPU 训练、环境配置、数据下载、CheXzero 调试相关的内容。

整理后的学习目标可以概括为:

  • 能判断远程机器是否有可用 GPU,以及 GPU 当前是否被训练任务占用。
  • 能理解 nvidia-sminvidia-smi dmon 的关键指标。
  • 能把 PyTorch 训练代码显式迁移到 cuda device。
  • 能用 wgettmux 和磁盘检查命令处理长时间、大规模数据下载。
  • 能理解 CheXzero 训练前的数据目录、依赖和常见报错。

2. 远程 GPU 环境准备

2.1 创建或激活 conda 环境

在组内 GPU 服务器上,通常需要为课程代码或项目代码单独创建环境,避免污染已有环境。

conda create -n cs197-gpu python=3.9
conda activate cs197-gpu

如果服务器上的 conda 尚未初始化,可能需要先运行:

conda init

有些预装 AMI 或服务器环境中会使用:

source activate pytorch

source activateconda activate 的目的都是激活环境;区别在于某些远程环境第一次连接时 conda shell hook 尚未配置好,source activate 更容易直接可用。

2.2 推荐的基本检查

进入服务器后,先确认当前机器、路径和磁盘空间:

hostname
pwd
df -h

含义如下:

命令 作用 何时使用
hostname 查看当前连接到哪台机器 防止误在本地或错误服务器上运行训练
pwd 查看当前工作目录 下载数据、运行脚本前确认路径
df -h 查看各挂载点磁盘空间,-h 表示 human-readable 下载大型数据集前确认空间是否足够

3. GPU 状态查看与监控

3.1 一次性查看 GPU 状态

最常用命令是:

nvidia-smi

示例输出:

❯ nvidia-smi
Fri Jul 10 11:52:35 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 575.57.08              Driver Version: 575.57.08      CUDA Version: 12.9     |
|-----------------------------------------+------------------------+----------------------|
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 5090        On  |   00000000:01:00.0 Off |                  N/A |
|  0%   37C    P8              7W /  575W |      15MiB /  32607MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A            2633      G   /usr/lib/xorg/Xorg                        4MiB |
+-----------------------------------------------------------------------------------------+

这份输出可以按几个区域理解:

字段 含义 解读方式
NVIDIA-SMI nvidia-smi 工具版本 主要用于确认工具可用
Driver Version NVIDIA driver 版本 影响 CUDA / PyTorch 兼容性
CUDA Version driver 支持的最高 CUDA runtime 版本 不是当前 PyTorch 一定使用的 CUDA 版本
GPU Name GPU 型号 例如 NVIDIA GeForce RTX 5090
Temp GPU 温度 长时间训练时需要关注是否异常过热
Pwr:Usage/Cap 当前功耗 / 最大功耗 可辅助判断 GPU 是否在工作
Memory-Usage 显存占用 判断模型、batch size 或其他进程是否占用显存
GPU-Util GPU 计算利用率 如果训练时长期接近 0%,说明代码可能没有真正使用 GPU,或瓶颈在数据加载
Processes 当前占用 GPU 的进程 用于识别谁在用显存,以及是否有残留进程

从示例看,显存只占用 15MiB / 32607MiBGPU-Util0%,说明 GPU 基本空闲。/usr/lib/xorg/Xorg 只占用少量显存,通常是图形系统进程,不是训练任务。

3.2 持续监控 GPU 状态

训练时可以每秒刷新一次:

watch -d -n 1 nvidia-smi

参数解释:

  • watch: 周期性执行后面的命令。
  • -n 1: 每 1 秒刷新一次。
  • -d: 高亮显示与上一次输出不同的部分,方便观察显存、功耗、利用率变化。
  • nvidia-smi: 被重复执行的实际命令。

这个命令适合在另一个 terminal 或 tmux pane 中长期观察训练是否真的用上 GPU。

3.3 使用 dmon 查看动态指标

nvidia-smi dmon 可以按行输出 GPU 动态指标,更适合观察趋势或复制日志。

nvidia-smi dmon -s pucm -d 1 -o T

参数解释:

  • dmon: device monitoring,以表格流形式监控设备。
  • -s pucm: 选择输出指标组。
    • p: power,即功耗相关指标。
    • u: utilization,即 GPU / memory / encoder / decoder 利用率。
    • c: clock,即显存频率和核心频率。
    • m: memory,即 framebuffer / BAR1 等显存信息。
  • -d 1: 每 1 秒采样一次。
  • -o T: 输出时间戳,方便对齐训练日志。

示例输出:

Time         gpu    pwr  gtemp  mtemp     sm    mem    enc    dec    jpg    ofa   mclk   pclk     fb   bar1   ccpm
#HH:MM:SS     Idx      W      C      C      %      %      %      %      %      %    MHz    MHz     MB     MB     MB
 16:18:56       0     17     40      -      0      0      0      0      0      0    810     24     15      3      0
 16:18:57       0     10     40      -      0      0      0      0      0      0    405     24     15      3      0
 16:18:58       0      9     39      -      0      0      0      0      0      0    405     24     15      3      0
 16:18:59       0      9     39      -      0      0      0      0      0      0    405     24     15      3      0
 16:19:00       0      9     39      -      0      0      0      0      0      0    405     24     15      3      0
 16:19:01       0      9     39      -      0      0      0      0      0      0    405     24     15      3      0
 16:19:02       0      9     39      -      0      0      0      0      0      0    405     25     15      3      0

常用指标解释:

指标 含义 观察重点
gpu GPU 编号 多卡机器上用于区分设备
pwr 当前功耗,单位 W 训练时通常会明显高于空闲状态
gtemp GPU core 温度 长时间高温需要关注散热
mtemp 显存温度 某些 GPU 不提供该值,会显示 -
sm Streaming Multiprocessor 利用率 近似反映核心计算繁忙程度
mem 显存带宽利用率 数据搬运或 memory-bound 任务会更高
mclk memory clock 显存频率
pclk processor / graphics clock GPU 核心频率
fb framebuffer memory 使用量,单位 MB 近似理解为显存占用
bar1 BAR1 memory 使用量 GPU 映射到 CPU 地址空间的内存窗口,通常不是训练调优的首要指标

如果训练运行时 smmempwr 都长期很低,而 CPU 或磁盘很忙,常见原因是 DataLoader 太慢、数据在 CPU 侧预处理过重,或代码没有把 model / tensor 移到 GPU。

4. 将训练代码迁移到 GPU

4.1 检查 CUDA 是否可用

PyTorch 代码需要显式检查 CUDA:

use_cuda = torch.cuda.is_available()

if use_cuda:
    device = torch.device("cuda")
else:
    device = torch.device("cpu")

这一步的作用是让代码在有 GPU 和没有 GPU 的机器上都能运行。不能只依赖机器有 GPU,因为 driver、CUDA、PyTorch 版本或环境变量都可能导致 torch.cuda.is_available()False

4.2 将 model 和 tensor 移到 device

模型创建后需要移动到 GPU:

model = Net().to(device)

训练和测试循环中,输入数据和标签也要移动到同一个 device:

def train(args, model, train_loader, optimizer, epoch, device):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        ...

def test(model, test_loader, device):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            ...

如果 model 在 GPU 上但 data 仍在 CPU 上,通常会出现 device mismatch 报错;如果两者都留在 CPU 上,即使服务器有 GPU,训练也不会自动加速。

4.3 为 DataLoader 设置 CUDA 相关参数

原教程示例中,在 CUDA 可用时会更新训练和测试的 DataLoader 参数:

use_cuda = torch.cuda.is_available()

if use_cuda:
    device = torch.device("cuda")
    cuda_kwargs = {"num_workers": 1, "shuffle": True}
    train_kwargs.update(cuda_kwargs)
    test_kwargs.update(cuda_kwargs)
else:
    device = torch.device("cpu")

注意:原教程片段里出现过 numworkers,实际 PyTorch DataLoader 参数名应为 num_workers

4.4 记录训练时间与 W&B 日志

为了比较 CPU、GPU、不同 batch size 或不同 num_workers 的速度,需要记录每个 epoch 的耗时:

import time

for epoch in range(1, args.epochs + 1):
    t0 = time.time()
    train(args, model, train_loader, optimizer, epoch, device)
    t_diff = time.time() - t0
    print(f"Elapsed time is {t_diff}")
    test_loss, test_acc = test(model, test_loader, device)
    scheduler.step()

如果使用 W&B,可以记录 loss、accuracy 和训练耗时:

import wandb

wandb.init(config={"train_args": train_kwargs, "test_args": test_kwargs})

for epoch in range(1, args.epochs + 1):
    t0 = time.time()
    train(args, model, train_loader, optimizer, epoch, device)
    t_diff = time.time() - t0
    test_loss, test_acc = test(model, test_loader, device)
    scheduler.step()
    wandb.log(
        {"test_loss": test_loss, "test_acc": test_acc, "time_taken": t_diff},
        step=epoch,
    )

wandb.finish()

5. 训练速度优化思路

5.1 判断瓶颈在哪里

GPU 训练慢不一定是 GPU 算力不够。常见瓶颈包括:

  • 代码没有真正使用 GPU。
  • batch size 太小,GPU 显存和计算单元没有被充分利用。
  • DataLoader 太慢,GPU 等待 CPU 读取和预处理数据。
  • 磁盘或网络文件系统读取慢。
  • PyTorch、CUDA、driver 版本不匹配。

建议同时观察:

  • nvidia-smi / nvidia-smi dmon 的 GPU 利用率和显存。
  • 训练日志中的每个 epoch 耗时。
  • CPU、磁盘和数据加载速度。

5.2 调整 batch size

如果显存占用很低,可以尝试增大 batch size:

python main_working.py --batch-size=128

原教程中提到,从默认 64 增加到 128 不一定显著加速,因为示例模型较小,主要瓶颈可能不是模型计算,而是数据加载或内存访问。实际项目中需要结合显存、loss 稳定性和吞吐量一起判断。

5.3 调整 num_workers

num_workers 控制 DataLoader 用多少个子进程加载数据。更多 worker 可以提前准备下一个 batch,让 GPU 不必等待数据读取。

原教程中,g5.4xlarge 的推荐尝试值是 16

train_kwargs.update({"num_workers": 16, "shuffle": True})

num_workers 不是越大越好。过大可能导致:

  • CPU 进程过多,反而上下文切换严重。
  • 内存占用上升。
  • 文件系统压力过大。
  • 在共享服务器上影响他人任务。

实践中可以从 124816 逐步试,并记录 epoch 时间。

6. 使用 wget 下载网络数据

6.1 下载整个目录的典型写法

PhysioNet 数据集通常需要递归下载,形式大致如下:

wget -r -N -c -np \
  --user YOUR_PHYSIONET_USERNAME \
  --ask-password \
  DATASET_URL

参数解释:

参数 含义
-r recursive,递归下载目录中的文件
-N timestamping,只下载远端更新过或本地不存在的文件
-c continue,断点续传
-np no-parent,不爬到上级目录
--user 指定需要认证的数据集用户名
--ask-password 交互式输入密码,避免把密码写进命令历史
DATASET_URL 数据集目录或文件链接

对于 PhysioNet,下载前通常需要登录账号并获得对应数据集权限。不要把账号、密码或 token 写入笔记正文或脚本。

6.2 下载前检查目录和空间

查看当前目录:

pwd

查看剩余磁盘空间:

df -h

下载大数据前尤其要确认:

  • 当前路径是否在预期的数据盘,而不是 home 目录的小配额空间。
  • 目标目录是否有足够空间。
  • 下载失败后是否可以用 wget -c 续传。

6.3 把下载任务放进 tmux

长时间下载应放在 tmux 中,避免 SSH 断开后任务中止:

tmux new -s download
wget -r -N -c -np \
  --user YOUR_PHYSIONET_USERNAME \
  --ask-password \
  DATASET_URL

常用操作:

操作 命令或快捷键 作用
新建 session tmux new -s download 创建名为 download 的会话
detach Ctrl-b 然后按 d 让任务在后台继续跑
查看 session tmux ls 列出已有会话
重新进入 tmux attach -t download 回到下载会话

7. CheXzero 与 MIMIC-CXR 数据准备

7.1 克隆 CheXzero

原教程后半部分使用 CheXzero 作为真实代码库示例:

git clone https://github.com/rajpurkarlab/CheXzero.git
cd CheXzero

如果远程服务器没有配置 GitHub SSH key,优先使用 HTTPS clone。

7.2 创建 CheXzero 环境并安装依赖

source activate base
conda create -n chexzero-demo python=3.9
conda activate chexzero-demo
pip install -r requirements.txt

原教程中提到可能遇到:

No matching distribution found for opencv-python-headless

原因是 requirements.txt 中固定的 opencv-python-headless==4.1.2.30 可能已经无法从 PyPI 获取。一个临时解决方式是去掉版本号,改成:

opencv-python-headless

这能绕过安装失败,但也可能引入依赖兼容性问题。更稳妥的方式是结合当前 Python 版本、PyTorch 版本和项目 README 重新锁定依赖。

7.3 下载 MIMIC-CXR 数据

CheXzero 训练需要 MIMIC-CXR 相关数据。原教程提到的入口是:

https://physionet.org/content/mimic-cxr-jpg/2.0.0/

完整数据很大,下载可能需要 12 小时以上。可以先下载小样本目录验证流程,再下载全量数据。

如果已经下载报告压缩包,可以解压:

unzip mimic-cxr-reports.zip

预处理时需要提供 chest X-ray 图像路径和 radiology reports 路径:

python run_preprocess.py \
  --chest_x_ray_path=data/physionet.org/files/mimic-cxr-jpg/2.0.0/files \
  --radiology_reports_path=data/physionet.org/files/mimic-cxr/2.0.0/files

预处理输出包括:

  • data/cxr_path.csv
  • data/cxr.h5
  • data/mimic_expressions.csv

其中 cxr.h5 是 HDF5 文件,用于高效缓存图像数据。原教程指出,使用 h5 文件可以显著减少训练时反复读取图像文件的开销。

7.4 检查 h5 文件

可以在 notebook 或 Python 脚本中检查:

import h5py

f1 = h5py.File("../data/cxr.h5", "r+")
list(f1.keys())
f1["cxr"]

示例输出:

<HDF5 dataset "cxr": shape (7, 320, 320), type "<f4">

这表示 h5 文件里有一个名为 cxr 的 dataset,包含 7 张胸片,每张被存为 320 x 320 的数组。

7.5 运行 CheXzero 训练

从 CheXzero 仓库根目录运行:

python run_train.py \
  --cxr_filepath "./data/cxr.h5" \
  --txt_filepath "data/mimic_impressions.csv"

训练前需要确认:

  • cxr.h5 路径正确。
  • mimic_impressions.csv 路径正确。
  • notebook 中没有同时打开同一个 h5 文件。
  • PyTorch / CUDA 版本与当前 GPU driver 兼容。

8. 常见问题与排查

8.1 nvidia-smi 不存在或报错

可能原因:

  • 当前机器没有 NVIDIA GPU。
  • NVIDIA driver 没有安装或没有正确加载。
  • 当前 shell / container 没有访问 GPU 的权限。

排查顺序:

hostname
nvidia-smi

先确认自己连接的是预期的 GPU 服务器,再检查 driver 和环境。

8.2 训练很慢但 GPU 空闲

常见原因:

  • 没有执行 model.to(device)
  • datatarget 没有执行 .to(device)
  • torch.cuda.is_available() 返回 False
  • DataLoader 太慢,GPU 在等数据。

排查方式:

  • 在代码中打印 device
  • watch -d -n 1 nvidia-smi 观察训练开始后显存和利用率是否变化。
  • 尝试增大 batch sizenum_workers,并记录每个 epoch 的耗时。

8.3 h5 文件无法打开

原教程提到一个常见问题:notebook 中已经打开了 cxr.h5,训练脚本再次打开时会报错。解决方式是关闭 notebook kernel,或在 notebook 中执行:

f1.close()

8.4 h5 key 名称不匹配

如果训练代码期待 cxr_unprocessed,但实际 h5 文件中的 key 是 cxr,会出现找不到对象的错误。可以先检查 key:

list(f1.keys())

再把训练代码中的 key 改为实际存在的名称,例如 cxr

8.5 CUDA 与 PyTorch 版本不匹配

如果遇到类似 “No kernel image is available for execution on the device” 的 CUDA 报错,需要检查当前 driver 支持的 CUDA 版本,以及安装的 PyTorch CUDA build。

查看 driver 侧 CUDA 信息:

nvidia-smi

必要时卸载并安装匹配版本的 PyTorch:

pip uninstall torch torchvision torchaudio
pip install torch==1.10.2+cu113 torchvision==0.11.3+cu113 torchaudio==0.10.2 \
  --extra-index-url https://download.pytorch.org/whl/cu113

具体版本应根据当前项目、Python 版本、GPU 型号和 driver 支持范围调整。

原始教程要点

原始教程完整覆盖了 AWS EC2 版本的流程,主要包括:

  • 使用 AWS EC2 创建 deep learning instance。
  • 选择 Deep Learning AMI GPU PyTorch 镜像和合适的 GPU instance type。
  • 创建 .pem key pair,并通过 chmod 400 修正私钥权限。
  • 配置 VS Code Remote-SSH 连接远程 instance。
  • 在远程环境中使用 screenrczshoh-my-zsh 改善开发体验。
  • 修改 PyTorch 训练代码,使 model、data 和 target 使用 cuda
  • 使用 W&B 记录训练指标和 epoch 耗时。
  • 通过 batch size、num_workers 和 DataLoader 优化训练吞吐。
  • 克隆并运行 CheXzero,处理 MIMIC-CXR 数据,排查依赖、h5 文件和 CUDA 版本问题。

这些内容在组内 GPU 服务器上仍然大多适用;需要替换的是 AWS instance 创建、key pair 和 EC2 连接部分。

Switch to English